#include <fstream>
#include <iostream>
#include <string>
#include <Zaf\String\FromString.h>
#include <Zaf\String\ToString.h>



struct RuntimeInfo {
	int SourceNumericalSystem;
	int DestinationNumericalSystem;
};

struct ArgumentFunctionTableEntry {
	const wchar_t* const Argument;
	bool HasValue;
	bool (*Function)(const wchar_t*);
};



bool SetSourceNumericalSystem(const wchar_t* value);
bool SetDestinatonNumericalSystem(const wchar_t* value);
int ScanArguments(int argc, const wchar_t* const* argv);
int CallArgumentFunction(int curIndex, int argc, const wchar_t* const* argv);
void ConvertFromInputStream(std::wistream& stream);
void ConvertFromFile(const wchar_t* fileName);
bool IsRuntimeInfoFilled();



ArgumentFunctionTableEntry g_argFuncTable[] = {
	L"-s", true, SetSourceNumericalSystem,
	L"-d", true, SetDestinatonNumericalSystem,
	nullptr, nullptr,
};

RuntimeInfo g_runtimeInfo;



int wmain(int argc, wchar_t** argv) {

	int fileNameIndex = ScanArguments(argc, argv);

	if (fileNameIndex == -1 || IsRuntimeInfoFilled() == false) {

		std::wcout << L"Zplutor's Programmer Toys" << std::endl;
		std::wcout << L"Numerical System Convertion" << std::endl;
		std::wcout << L"Version 0.0.2" << std::endl << std::endl;
		std::wcout << L"Usage: nsc -s <src> -d <dst> [fileName] ..." << std::endl;
		return -1;
	}

	if (fileNameIndex == argc) {

		ConvertFromInputStream(std::wcin);
	}
	else {

		for (int index = fileNameIndex; index < argc; ++index) {

			ConvertFromFile(argv[index]);
		}
	}

	return 0;
}



int ScanArguments(int argc, const wchar_t* const* argv) {

	int index = 1;
	while (index < argc) {

		if (argv[index][0] == L'-') {

			int valueCount = CallArgumentFunction(index, argc, argv);

			if (valueCount == -1) {
				return -1;
			}

			index += valueCount + 1;
		}
		else {
			return index;
		}
	}

	return index;
}



int CallArgumentFunction(int curIndex, int argc, const wchar_t* const* argv) {

	int tableIndex = 0;
	while (g_argFuncTable[tableIndex].Argument != nullptr) {

		if (wcscmp(argv[curIndex], g_argFuncTable[tableIndex].Argument) == 0) {

			if (g_argFuncTable[tableIndex].HasValue == true && curIndex == argc - 1) {
				return -1;
			}

			if (g_argFuncTable[tableIndex].Function(argv[curIndex + 1]) == true) {
				return g_argFuncTable[tableIndex].HasValue ? 1 : 0;
			}
			
			return -1;
		}

		++tableIndex;
	}

	return -1;
}



bool SetSourceNumericalSystem(const wchar_t* value) {

	unsigned int source = Zaf::String::FromString<unsigned int>(value);

	if (source == 0) {
		return false;
	}

	g_runtimeInfo.SourceNumericalSystem = source;

	return true;
}



bool SetDestinatonNumericalSystem(const wchar_t* value) {

	unsigned int destination = Zaf::String::FromString<unsigned int>(value);

	if (destination == 0) {
		return false;
	}

	g_runtimeInfo.DestinationNumericalSystem = destination;

	return true;
}



bool IsRuntimeInfoFilled() {
	return g_runtimeInfo.SourceNumericalSystem != 0 && g_runtimeInfo.DestinationNumericalSystem != 0;
}


void ConvertFromInputStream(std::wistream& stream) {
	
	std::wstring word;
	while(stream >> word) {

		long long value = 0;
		if (Zaf::String::TryFromString(word, value, g_runtimeInfo.SourceNumericalSystem) == true) {

			std::wcout << Zaf::String::ToString<wchar_t>(value, g_runtimeInfo.DestinationNumericalSystem);
		}

		std::wcout << std::endl;
	}
}



void ConvertFromFile(const wchar_t* fileName) {

	std::wifstream fileStream(fileName, std::ios::in);

	ConvertFromInputStream(fileStream);

	fileStream.close();
}